package cn.ingenic.glasssync.contacts;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import cn.ingenic.glasssync.contact.ContactsProvider;
import cn.ingenic.glasssync.contacts.aidl.IContactsCallback;
import cn.ingenic.glasssync.contacts.aidl.IContactsService;
import cn.ingenic.glasssync.db.ContactsDBHelper;
import cn.ingenic.glasssync.R;
import com.ingenic.glass.voicerecognizer.api.VoiceRecognizer;
import com.ingenic.glass.voicerecognizer.api.VoiceRecognizerListener;

public class ContactsService extends Service {
	private String TAG = "ContactsService";
        private static final boolean DEBUG = false;
	public static final int TYPE_START = 0;
	public static final int TYPE_ADD = 1;
	public static final int TYPE_DELNAME = 2;
	public static final int TYPE_DELPHONE = 3;
	public static final int TYPE_STOP = 4;
        public static final int TYPE_ROLLBACK = 5;
        public static final int TYPE_CLEAR_ALL = 6;
	public static final String MIMETYPE_DIR = "vnd.android.cursor.dir/";
	public static final String MIMETYPE_ITEM = "vnd.android.cursor.item/";

	public static final String DATA_TYPE_PHONE = "phone"; // phone number
        public static final int CN_PREFIX_LENGTH = 5;
	private Context mContext = null;
	private ContentResolver mResolver = null;
	private SQLiteDatabase mContactDB = null;
	private PowerManager.WakeLock mWakeLock = null;
        private VoiceRecognizer mVoiceRecognizer = null;
        private IContactsCallback mIContactsCallback;
	private BlockingQueue<byte[]> mSyncDataQueue = null;
        private byte[] mByteBack = new byte[5];
	private int mBondState = 0; // 1 is binded; 0 is unbind
        private int mSendContactsCount = 0;
        private int mReceiveContactsCount = 0;
        private boolean mIsBindIosDevice;
	private static final int MSG_RECEIVE_CONTACT_TIMEOUT = 1;
	private int TIMEOUT_MS = 1000 * 10; // 10s
        public Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
		    if (DEBUG)Log.d(TAG, "ContactsService msg.what="+msg.what);
		    switch (msg.what) {
		    case MSG_RECEIVE_CONTACT_TIMEOUT:
			mSyncDataQueue.clear();
			mSyncDataQueue.offer(mByteBack);
			break;
		    default:
			break;
		    }
		    super.handleMessage(msg);
		}
	    };
	@Override
	public IBinder onBind(Intent arg0) {
	        if (DEBUG)Log.d(TAG, "ContactsService onBind");
		return mBinder;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		if (DEBUG)Log.d(TAG, "ContactsService onCreate");
		mContext = this;
		System.arraycopy(mByteBack, 0, "<CN>".getBytes(), 0, 4);
		mByteBack[4] = (byte)5;
		mResolver = mContext.getContentResolver();
		String bond_addr = Settings.System.getString(mResolver,"glasssync_bond_addr");
		if(null == bond_addr || bond_addr.equals("")){
		    mBondState = 0;
		    mIsBindIosDevice = false;
		}else if(bond_addr.indexOf("-")<0){
		    mIsBindIosDevice = false;
		    mBondState = 1;
		}else{
		    mIsBindIosDevice = true;
		    mBondState = 1;
		}
		Uri bindStateUri = Settings.System.getUriFor("glasssync_bond_addr");
		mResolver.registerContentObserver(bindStateUri,false,mContentObserver);
		mSyncDataQueue = new LinkedBlockingQueue<byte[]>();
		new Thread(new HandleQueue()).start();
		SQLiteOpenHelper dBHelper = ContactsDBHelper.getInstance(mContext, null);
		mContactDB = dBHelper.getWritableDatabase();
		PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
		mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mContext.getClass().getName());
		mVoiceRecognizer = new VoiceRecognizer(VoiceRecognizer.REC_TYPE_COMMAND, 
						       new VoiceRecognizerListener());
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if (DEBUG)Log.d(TAG, "ContactsService onDestroy");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (DEBUG)Log.d(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);

	}

	private IContactsService.Stub mBinder = new IContactsService.Stub() {

		@Override
		public boolean sendContactsData(byte[] by) throws RemoteException {
			mSyncDataQueue.offer(by);
			return true;
		}

		@Override
		public boolean registerCallback(IContactsCallback callback){
		        mIContactsCallback = callback;
		        return true;
		}
	};

	class HandleQueue implements Runnable {
	        
		@Override
		public void run() {
			byte[] data;
			int type;
			while (!Thread.interrupted()) {
				try {
					data = mSyncDataQueue.take();
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
				type = data[4] & 0xFF;
				if (DEBUG)Log.d(TAG, "contact mSyncDataQueue type=" + type);
				syncContacts(type, data);
			}
		}

	        private void syncContacts(int type, byte[] by) {
		    if (DEBUG)Log.d(TAG, "syncContacts type =" + type + " inTransaction="
			  +mContactDB.inTransaction());
		    switch (type) {
		    case TYPE_START:
			  //开始发送联系人数据
			if (mContactDB.inTransaction())
			    return;
			mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
			mHandler.sendEmptyMessageDelayed(MSG_RECEIVE_CONTACT_TIMEOUT,TIMEOUT_MS);
			int countLength= by.length - CN_PREFIX_LENGTH;
			byte[] countByte = new byte[countLength];
			try {
				System.arraycopy(by, CN_PREFIX_LENGTH, countByte, 0, countLength);
				String count = new String(countByte, "GBK");
				  //联系人数据总共数量
				mSendContactsCount = Integer.parseInt(count);
			} catch (Exception e) {
				e.printStackTrace();
			}	
			if (!mWakeLock.isHeld())
				mWakeLock.acquire();
			mContactDB.beginTransaction();
			break;
		    case TYPE_ADD:
			//添加联系人
			if (!mContactDB.inTransaction() || 0 == mBondState)
			    return;
			mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
			mHandler.sendEmptyMessageDelayed(MSG_RECEIVE_CONTACT_TIMEOUT,
							 TIMEOUT_MS);
			add(by);
			break;
		    case TYPE_DELNAME:
			//删除联系人
			if (!mContactDB.inTransaction() || 0 == mBondState)
			    return;
			mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
			mHandler.sendEmptyMessageDelayed(MSG_RECEIVE_CONTACT_TIMEOUT,
							 TIMEOUT_MS);
			delN(by);
			break;
		    case TYPE_DELPHONE:
			//删除联系人某电话
			if (!mContactDB.inTransaction() || 0 == mBondState)
			    return;
			mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
			mHandler.sendEmptyMessageDelayed(MSG_RECEIVE_CONTACT_TIMEOUT,
							 TIMEOUT_MS);
			delP(by);
			break;
		    case TYPE_STOP:
			  //联系人同步完成
			commit();
			break;
		    case TYPE_ROLLBACK:
			rollBack();
			break;
		    default:
			Log.w(TAG, "Unknow type: " + type);
			break;
		    }
		}       
	}
      //收到ios发送的联系人同步完成命令
        private void commit(){
	    if (DEBUG)Log.d(TAG, "commit inTransaction=" +mContactDB.inTransaction()+",mBondState="+mBondState);
	    if (DEBUG)Log.d(TAG, "commit mSendContactsCount="+mSendContactsCount+",mReceiveContactsCount=" +mReceiveContactsCount);
	    if (!mContactDB.inTransaction() || 0 == mBondState)
		return;
	    mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
	      //如果真正收到的联系人数量和ios发送的数量不相等,则删除数据库，向手机发送命令，让手机重传
	    if(mReceiveContactsCount != mSendContactsCount){
		mContactDB.endTransaction();
		try{
		    mResolver.delete(ContactsProvider.URI_CLEARALL, null, null);
		    mIContactsCallback.sendRetrySyncContacts();
		} catch (RemoteException e) {
		    e.printStackTrace();
		}
	    } else {
		mContactDB.setTransactionSuccessful();
		mContactDB.endTransaction();
	    }
	    mReceiveContactsCount = 0;
	    mSendContactsCount = 0;
	    mWakeLock.release();
	    int contactCount = 0;
	    String[] contactsCols = new String [] { "_id", "display_name" };
	    Cursor cursor = mResolver.query(ContactsProvider.URI_CONTACTS, 
					    contactsCols, null, null, null);
	    if (null != cursor) {
		contactCount = cursor.getCount();
		cursor.close();
	    }
	    if (contactCount > 0) {
		String tts = String.format(mContext.getString(R.string.tts_contact_sync_ok), 
					   ""+contactCount);
		mVoiceRecognizer.playTTS(tts);
	    }
	}
        //解绑时和超时未收到联系人数据时调用
        private void rollBack() {
	    if (DEBUG)Log.d(TAG, "rollBack inTransaction=" +mContactDB.inTransaction()+",mBondState="+mBondState);
	    if (mContactDB.inTransaction()) {
		mSyncDataQueue.clear();
		mHandler.removeMessages(MSG_RECEIVE_CONTACT_TIMEOUT);
		mContactDB.endTransaction();
		mWakeLock.release();
		  //超时,则删除数据库，向手机发送命令，让手机重传.
		mResolver.delete(ContactsProvider.URI_CLEARALL, null, null);
		try{
		    mIContactsCallback.sendRetrySyncContacts();
		} catch (RemoteException e) {
		    e.printStackTrace();
		}
		mReceiveContactsCount = 0;
		mSendContactsCount = 0;
	    }
	    if(mIsBindIosDevice && mBondState == 0){
		  //解绑时和超时未收到联系人数据时,并且之前绑定的是ios设备 调用
		mResolver.delete(ContactsProvider.URI_CLEARALL, null, null);
	    }
	}
      //将各条联系人数据分隔开来
	private void add(byte[] by) {
		int position = CN_PREFIX_LENGTH;
		int count = (int) by[position++];
		if (DEBUG)Log.d(TAG, "add count=" + count);
		for (int i = 0; i < count; ++i) {
			if (DEBUG)Log.d(TAG, "byte=" + new String(by) + ",i=" + i + ",count=" + count);
			mReceiveContactsCount++;
			int nameLength = (int) by[position++];;
			byte[] namebyte = new byte[nameLength];
			try {
				System.arraycopy(by, position, namebyte, 0, nameLength);
				position += nameLength;
				int numberLength = (int) by[position++];
				byte[] numberbyte = new byte[numberLength];
				System.arraycopy(by, position, numberbyte, 0, numberLength);
				position += numberLength;
				String name = new String(namebyte, "GBK");
				String number = new String(numberbyte, "GBK");
				addContacts(name, number);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
	}

	private void delN(byte[] by) {
		int position = CN_PREFIX_LENGTH;
		int count = (int) by[position++];
		if (DEBUG)Log.d(TAG, "del name count=" + count);
		for (int i = 0; i < count; i++) {
		        mReceiveContactsCount++;
			int nameLength = (int) by[position++];
			byte[] namebyte = new byte[nameLength];
			try {
				System.arraycopy(by, position, namebyte, 0, nameLength);
				position += nameLength;
				String name = new String(namebyte, "GBK");
				delContacts(name);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
	}

	private void delP(byte[] by) {
		int position = CN_PREFIX_LENGTH;
		int count = (int) by[position++];
		if (DEBUG)Log.d(TAG, "del phone count=" + count);
		for (int i = 0; i < count; i++) {
		        mReceiveContactsCount++;
			int nameLength = (int) by[position++];
			byte[] namebyte = new byte[nameLength];
			try {
				System.arraycopy(by, position, namebyte, 0, nameLength);
				position += nameLength;
				int numberLength = (int) by[position++];
				byte[] numberbyte = new byte[numberLength];
				System.arraycopy(by, position, numberbyte, 0, numberLength);
				position += numberLength;
				String name = new String(namebyte, "GBK");
				String number = new String(numberbyte, "GBK");
				delPhone(name, number);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
	}

	private long queryContactId(String displayName) {
		long contact_id = -1;
		Cursor cursor = mResolver.query(ContactsProvider.URI_CONTACTS,
				new String[] { "_id" }, " display_name = ? ",
				new String[] { displayName }, null);
		if (null != cursor) {
			if (cursor.moveToFirst()) {
				contact_id = cursor.getLong(cursor.getColumnIndex("_id"));
			}
			cursor.close();
		}
		return contact_id;
	}

	private void addContacts(String name, String phone) {
	        if(0 == mBondState)return;
		ContentValues values = new ContentValues();
		long contact_id = -1;
		phone = phone.replaceAll("-", "").replaceAll(" ", "");
		contact_id = queryContactId(name);
		if (DEBUG)Log.d(TAG, "contact_id = " + contact_id + ", name = " + name
				+ ", phone = " + phone);
		if (contact_id < 0) { // contents is not exists.
			// Insert to CONTACTS table.
			values.put(ContactsProvider.KEY_CONTACTS_DISPLAYNAME, name);
			Uri contactUri = mResolver.insert(ContactsProvider.URI_CONTACTS,
					values);
			contact_id = ContentUris.parseId(contactUri);
			if (contact_id >= 0) {
				mResolver.notifyChange(ContactsProvider.URI_CONTACTS, null);
			}
			values.clear();
		}

		if (contact_id >= 0) {
			// Insert to DATA table.
			values.put(ContactsProvider.KEY_DATA_CONTACTID, contact_id);
			values.put(ContactsProvider.KEY_DATA_MIMETYPE, MIMETYPE_ITEM);
			values.put(ContactsProvider.KEY_DATA_TYPE, DATA_TYPE_PHONE);
			values.put(ContactsProvider.KEY_DATA_DATA, phone);
			Uri dataUri = mResolver.insert(ContactsProvider.URI_DATA, values);
			if (ContentUris.parseId(dataUri) >= 0) {
				mResolver.notifyChange(ContactsProvider.URI_DATA, null);
			}
		}
	}

	private void delContacts(String name) {
	        if(0 == mBondState)return;
		long contact_id = queryContactId(name);
		if (DEBUG)Log.d(TAG, "delContacts() in, contact_id = " + contact_id);
		int lines = 0;
		lines = mResolver.delete(ContactsProvider.URI_CONTACTS, " _id = ? ",
				new String[] { contact_id + "" });
		if (lines > 0) {
			mResolver.notifyChange(ContactsProvider.URI_CONTACTS, null);
			;
		}
		lines = mResolver.delete(ContactsProvider.URI_DATA, " contact_id = ? ",
				new String[] { contact_id + "" });
		if (lines > 0) {
			mResolver.notifyChange(ContactsProvider.URI_DATA, null);
		}
	}

	private void delPhone(String name, String phone) {
	        if(0 == mBondState)return;
		long contact_id = queryContactId(name);
		if (DEBUG)Log.d(TAG, "delPhone() in, contact_id=" + contact_id + ", phone="
				+ phone);
		if (TextUtils.isEmpty(phone)) {
			return;
		}
		phone = phone.replaceAll("-", "").replaceAll(" ", "");
		int lines = 0;
		lines = mResolver.delete(ContactsProvider.URI_DATA,
				" contact_id = ? AND type = ? AND data = ? ", new String[] {
						contact_id + "", DATA_TYPE_PHONE, phone });
		if (lines > 0) {
			mResolver.notifyChange(ContactsProvider.URI_DATA, null);
		}
	}

	private ContentObserver mContentObserver = new ContentObserver(
			new Handler()) {
		@Override
		public void onChange(boolean selfChange) {
			super.onChange(selfChange);
			  //监听解绑，记录是否绑定的是ios设备
			String bond_addr = Settings.System.getString(mResolver,"glasssync_bond_addr");
			if (DEBUG)Log.d(TAG,"bond_addr="+bond_addr+",mIsBindIoSDevice="+mIsBindIosDevice);
                        if(null == bond_addr || bond_addr.equals("")){
			        mBondState = 0;
                                mSyncDataQueue.clear();
				mSyncDataQueue.offer(mByteBack);
                        }else if(bond_addr.indexOf("-")<0){
			    mIsBindIosDevice = false;
			    mBondState = 1;
			}else{
			    mIsBindIosDevice = true;
			    mBondState = 1;
			}
		}
	};
}
